<script setup lang="ts">
import {Message, messageStore, MessageType, SessionType} from "../store";
import {ref} from "vue";
import {createGPTRequest} from "../chatGptUtils";
import {fetchEventSource} from "@microsoft/fetch-event-source";

const formatDate = (d: Date): string => {
  const year = d.getFullYear()
  const month = d.getMonth() + 1 // 月份从0开始，所以要加1
  const day = d.getDate()
  const hour = d.getHours()
  const minute = d.getMinutes()
  return `${year}-${month}-${day} ${hour}:${minute}`
}
const store = messageStore()
const map = store.getMsgMap()
const hisMsg = store.getErnieHistoryMessage()

console.log(store.getUserMapper()?.get(store.getUserInfo().id)?.avatar)
const myself = store.getUserInfo();
let text = ref<string>("");
const getUid = (): number => {
  const res = 'xxxxxxxxxxxyxxxxxxxx'.replace(/[xy]/g, function (c) {
    const r = Math.random() * 16 | 0,
        v = c === 'x' ? r : (r & 0x3 | 0x8);
    return v.toString(16);
  });
  return parseInt(res, 10);
}
const messageFactory = (msg: string, msgT: SessionType): Message => {
  return {
    messageId: getUid(),
    fromId: myself.id,
    toId: store.getCurrentUserId,
    text: msg,
    msgType: MessageType.TEXT,
    sessionType: msgT,
    msgDate: new Date(),
  }
}

const receiveMessageFactory = (msg: string, sessionT: SessionType) => {
  return {
    messageId: getUid(),
    fromId: store.getCurrentUserId,
    toId: myself.id,
    text: msg,
    msgType: MessageType.TEXT,
    sessionType: sessionT,
    msgDate: new Date(),
  }
}

const ernieToken = window.localStorage.getItem('ernie-chat-token')

let completeFlag: boolean = true

const sendGPTRequest = (text: string) => {
  store.getMsgMap().get(store.getCurrentUserId)?.push(receiveMessageFactory("", SessionType.GPT))
  const mlist = store.getMsgMap().get(store.getCurrentUserId)
  const idx: number = mlist!.length
  completeFlag = false
  const gptRequest = createGPTRequest(text, store)
  try {
    // xhr.open("POST", "https://aip.baidubce.com/rpc/2.0/ai_custom/v1/wenxinworkshop/chat/completions_pro?access_token=24.4fe0f7d7cb9b4b84f60ca1b880c96143.2592000.1716722592.282335-64071941");
    // xhr.open("POST", "http://localhost:8080/ernie")
    // xhr.setRequestHeader("Content-Type", "application/json")
    // xhr.setRequestHeader("Accept", "event-stream/text")

    fetchEventSource(import.meta.env.VITE_ERNIE_BOT_INTERFACE, {
      method: 'POST',
      headers: {
        "Content-Type": "application/json",
        "Accept": "event-stream/text",
        "ernie-chat-token": ernieToken!
      },
      body: JSON.stringify(gptRequest),
      onmessage(event) {
        let newData = event.data
        let jsonData = null
        try {
          jsonData = JSON.parse(newData);
        } catch (e) {
          console.log(newData)
        }
        if (jsonData !== null && jsonData.result !== undefined && jsonData.result !== '') {
          mlist![idx - 1].text += jsonData.result;
        }
        const box = document.querySelector('.messageWindow') as HTMLElement
        setTimeout(() => box.scrollTop = box.scrollHeight);
      },
      onerror(event) {
        mlist![idx - 1].text += `出错啦！请重试！\n`
        hisMsg.pop()
        completeFlag = true
        console.log("服务异常", event)
        throw new Error("maybe Unauthorized")
      },
      onclose() {
        console.log('DONE')
        if (hisMsg.length >= 7)
          hisMsg.shift()
        hisMsg.push({role: 'assistant', content: mlist![idx - 1].text.slice()})
        console.log("服务关闭");
        completeFlag = true
      },
    })
  } catch (err) {
    console.log(err)
  }
}


const sendMessage = () => {
  if (!completeFlag || text.value === '') {
    setTimeout(() => text.value = "")
    return;
  }
  const msg = messageFactory(text.value, SessionType.PRIVATE)

  store.getMsgMap().get(msg.toId)?.push(msg)
  if (store.getCurrentUserId === 121212) {
    if (hisMsg.length >= 7)
      hisMsg.shift()
    hisMsg.push({role: 'user', content: msg.text.slice()})
    console.log(hisMsg)
    sendGPTRequest(msg.text)
  }

  const box = document.querySelector('.messageWindow') as HTMLElement
  setTimeout(() => box.scrollTop = box.scrollHeight)
  setTimeout(() => text.value = "")
}

const handleKeyDown = (event: any) => {
  if (event.shiftKey && (event.keyCode === 13 || event.key === 'Enter')) {
    return;
  } else if (event.key === 'Enter') {
    sendMessage()
  }
}

</script>

<template>
  <div id="frameBox">
    <div class="messageWindow">
      <transition-group name="list" tag="ul">
        <li v-for="(msg, idx) in map.get(store.getCurrentUserId)" :key="idx">
          <img v-if="msg.fromId === store.getUserInfo().id" alt="avatar" class="avatar avatar_r" :src="myself.avatar">
          <img v-else alt="avatar" class="avatar avatar_l"
               :src="store.getUserMapper()?.get(store.getCurrentUserId)?.avatar">
          <div v-if="msg.fromId === store.getUserInfo().id" class="msg msg_r">{{ msg.text }}</div>
          <div v-else class="msg msg_l">{{ msg.text }}</div>
          <div v-if="msg.fromId === store.getUserInfo().id" class="msgDate" style="right: 50px">
            {{ formatDate(msg.msgDate) }}
          </div>
          <div v-else class="msgDate" style="left: 50px;">{{ formatDate(msg.msgDate) }}</div>
        </li>
      </transition-group>
    </div>
    <div class="inputFrame flex_col_center">
      <div class="option">

      </div>
      <div class="textBox flex_row_center">
        <textarea v-model="text" @keydown="handleKeyDown"></textarea>
      </div>
      <div class="btnBox">
        <div class="btn" @click="sendMessage()">发送</div>
      </div>
    </div>
  </div>
</template>

<style scoped>

.list-move, /* 对移动中的元素应用的过渡 */
.list-enter-active,
.list-leave-active {
  transition: all 0.5s ease;
}

.list-enter-from,
.list-leave-to {
  opacity: 0;
  transform: translateX(30px);
}

/* 确保将离开的元素从布局流中删除
  以便能够正确地计算移动的动画。 */
.list-leave-active {
  position: absolute;
}

.flex_row_center {
  display: flex;
  justify-content: center;
  flex-direction: row;
  align-items: center;
}

.flex_col_center {
  display: flex;
  justify-content: center;
  flex-direction: column;
  align-items: center;
}

#frameBox {
  height: calc(100% - 40px);
  width: 100%;
  position: relative;

  .messageWindow {
    height: calc(100% - 210px);
    padding: 15px;
    overflow: auto;
    color: white;

    li {
      margin-top: 20px;
      position: relative;

      .msgDate {
        position: absolute;
        right: 50px;
        bottom: 0;
        color: var(--msg-date);
        font-size: 10px;
      }

      .avatar {

        height: 40px;
        width: 40px;
        border-radius: 50%;
      }

      .avatar_r {
        float: right;
      }

      .avatar_l {
        float: left;
      }

      .msg {
        white-space: pre-wrap;
        word-break: break-all;
        background-color: #fa3b56;
        max-width: 50%;
        padding: 8px;
        font-size: 16px;
        border-radius: 8px;
        margin-top: 5px;
        margin-bottom: 20px;
      }

      .msg_r {
        margin-right: 7px;
        float: right;
      }

      .msg_l {
        margin-left: 7px;
        float: left;
      }
    }

    &::-webkit-scrollbar {
      width: 4px;
      background-color: rgba(0, 0, 0, 0);
    }

    &::-webkit-scrollbar-thumb {
      background: #fa3b56;
      border-radius: 4px;
    }
  }

  .inputFrame {
    position: absolute;
    bottom: 0;
    height: 170px;
    width: 100%;
    border-top: var(--border) solid 1px;

    .option {
      height: 20%;
      width: 100%;
    }

    .textBox {
      height: 60%;
      width: 100%;

      textarea {
        width: 95%;
        height: 100%;
        resize: none;
        background-color: var(--color-chat-bg);
        color: var(--color-font);
        font-size: 17px;

        &:focus {
          outline: none;
        }
      }
    }

    .btnBox {
      height: 20%;
      width: 100%;

      .btn {
        width: 70px;
        height: 90%;
        background-color: #fa3b56;
        color: white;
        float: right;
        border-radius: 8px;
        margin-right: 10px;
        line-height: 30px;
        text-align: center;

        &:active {
          background-color: blue;
        }
      }
    }
  }
}
</style>